<?php

class CandidateGroup extends AppModel
{

	public $name = 'CandidateGroup';

	public $displayField = 'name';

	public $validate = array(
        'name' => array(
            'create_first' => array(
                'on' => 'create',
                'required' => true,
                'allowEmpty' => false,
                'message' => 'required',
            ),
            'update_first' => array(
                'on' => 'update',
                'required' => false,
                'allowEmpty' => false,
                'message' => 'required',
            ),
        ),
	);

	public $hasMany = array(
		'Candidates' => array('className' => 'Candidate', 'dependent' => true),
	);

	public $belongsTo = array(
        'Client' => array('className' => 'Client'),
	);

	/**
	 * Проверяет возможность удаления данной группы.
	 *
	 * @param array $fields Поля данной группы
	 *
	 * @return bool
	 */
	function allowDelete($fields = null)
	{
	    if (!isset($fields)) {
	        return true;
	    }
	    if (empty($fields[$this->primaryKey])) {
	        return false;
	    }
	    $this->Candidates->rel();
        return !(bool)$this->Candidates->find(array("`".Inflector::underscore($this->name)."_id`" => $fields[$this->primaryKey]));
	}

	/**
	 * Проверяет возможность редактирования данной группы.
	 *
	 * @param array $fields Поля данной группы
	 *
	 * @return bool
	 */
	function allowUpdate($fields = null)
	{
        return true;
	}

	/**
	 * Возвращает ассоциативный массив групп кандидатов.
	 *
	 * @param array $conds
	 *
	 * @return array
	 */
	function generateList($conds = array())
	{
	    if (Auth::o()->is('client_admin')) {
	        $auth_data = Auth::o()->data();
            $conds[]["`{$this->name}`.`client_id`"] = $auth_data["client_id"];
	    }
	    $this->rel();
        return parent::generateList($conds, $this->primaryKey, null, "{n}.{$this->name}.{$this->primaryKey}", "{n}.{$this->name}.{$this->displayField}");
	}

	/**
	 * Возвращает список инструментов доступных данному клиенту по идентификаторц группы.
	 *
	 * @param int $id Идентификатор группы
	 *
	 * @return array
	 */
    function getToolsFor($id)
	{
        $conds = array();
        $conds[]["`{$this->name}`.`{$this->primaryKey}`"] = $id;
        if (Auth::o()->is('client_admin')) {
            $auth_data = Auth::o()->data();
            $conds[]["`{$this->name}`.`client_id`"] = $auth_data['client_id'];
        }
	    $this->rel();
	    $client_id = $this->field("client_id", $conds);
        if (empty($client_id)) {
            return array();
        }

	    $tools = $this->getModel('Client')->getToolsFor($client_id);
        if (empty($tools)) {
            return array();
        }

        return $tools;
	}

	/**
	 * Проверяет возможность назначения инструмента $tool_id группе $group_id.
	 * Если можно назначить инструмент хоть одному кандидату из группы, — вернёт true.
	 *
	 * @param int $tool_id Идентификатор инструмента
	 * @param int $group_id Идентификатор группы
	 *
	 * @return bool
	 */
    function isAllowTestFor($group_id, $tool_id, $candidate_id = null)
	{
	    if (isset($candidate_id)) {
	        return $this->numBusyCandidatesForTool($tool_id, null, $candidate_id) === 0;
	    } else {
            return $this->numAllowCandidatesForTool($tool_id, $group_id) > 0;
	    }
	}

	/**
	 * Возвращает количество кандидатов данной группы, которым нельзя назначить инструмент $tool_id.
	 *
	 * @param int $tool_id Идентификатор инструмента
	 * @param int $group_id Идентификатор группы
	 *
	 * @return int
	 */
    function numBusyCandidatesForTool($tool_id, $group_id, $candidate_id = null, $list_of_ids = false)
	{
        $Testing =& $this->getModel('Testing'); /* @var $Testing Testing */
        $Testing->rel('Candidate');

        /**
    	 * !!! Т У Т   Н А К Л А Д Ы В А Ю Т С Я   У С Л О В И Я  !!!
    	 *     Н А   Р А З Р Е Ш Е Н И Е   П Р О Х О Д Ж Е Н И Я
    	 *               К А Н Д И Д А Т О М   Т Е С Т А
         */
        $conds = array();
        $conds[]["`Testing`.`test_id`"] = $tool_id;
        if (isset($candidate_id)) {
            $conds[]["`Testing`.`candidate_id`"] = $candidate_id;
        } else {
            $conds[]["`Candidate`.`candidate_group_id`"] = $group_id;
        }
        if (Auth::o()->is('client_admin')) {
            $auth_data = Auth::o()->data();
            $conds[]["`Testing`.`client_id`"] = $auth_data['client_id'];
        }

        if ($list_of_ids) {
            $appointed_candidates = $Testing->findAll($conds, "DISTINCT `Candidate`.`id`");
            $appointed_candidates = !empty($appointed_candidates) ? $appointed_candidates : array();
            foreach ($appointed_candidates as &$row) {
                $row = intval($row['Candidate']['id']);
            }

            return $appointed_candidates;
        } else {
            $appointed_candidates = $Testing->find($conds, "COUNT(DISTINCT `Testing`.`candidate_id`) AS `count`");
            $appointed_candidates = !empty($appointed_candidates[0]['count']) ? intval($appointed_candidates[0]['count']) : 0;

            return $appointed_candidates;
        }
	}

	/**
	 * Возвращает список кандидатов указаной груммы, которым можно назначить указанный инструмент.
	 *
	 * @param int $tool_id Идентификатор инструмента
	 * @param int $group_id Идентификатор группы
	 * @return array
	 */
    function getAllowCandidatesForTool($tool_id, $group_id)
    {
        $Candidate =& $this->getModel('Candidate'); /* @var $Candidate Candidate */
        $busy_candidates_ids = $this->numBusyCandidatesForTool($tool_id, $group_id, null, true);

        $conds = array();
        $conds[]["`Candidate`.`candidate_group_id`"] = $group_id;
        $conds[]["not"]["`Candidate`.`id`"] = $busy_candidates_ids;
        if (Auth::o()->is('client_admin')) {
            $auth_data = Auth::o()->data();
            $conds[]["`Candidate`.`client_id`"] = $auth_data['client_id'];
        }

        $Candidate->rel();
        $candidates = $Candidate->findAll($conds);
        $candidates = !empty($candidates) ? $candidates : array();

        return $candidates;
    }

	/**
	 * Возвращает количество кандидатов, которым можно назначить инструмент $tool_id.
	 *
	 * @param int $tool_id Идентификатор инструмента
	 * @param int $group_id Идентификатор группы
	 *
	 * @return int
	 */
    function numAllowCandidatesForTool($tool_id, $group_id)
	{
        return $this->numCandidatesFor($group_id) - $this->numBusyCandidatesForTool($tool_id, $group_id);
	}

	/**
	 * Возвращает количество кандидатов в данной группе.
	 *
	 * @param int $group_id Идентификатор группы
	 *
	 * @return int
	 */
    function numCandidatesFor($group_id)
	{
        $Candidate =& $this->getModel('Candidate'); /* @var $Candidate Candidate */
        $Candidate->rel();

        $conds = array();
        $conds[]["`Candidate`.`candidate_group_id`"] = $group_id;
        if (Auth::o()->is('client_admin')) {
            $auth_data = Auth::o()->data();
            $conds[]["`Candidate`.`client_id`"] = $auth_data['client_id'];
        }
        return intval($Candidate->findCount($conds));
	}

	/**
	 * Возвращает список инструментов для назначения.
	 *
	 * @param int $id Идентификатор группы
	 *
	 * @return array
	 */
    function getToolsToAppointFor($id)
	{
	    $tools = $this->getToolsFor($id);
        foreach ($tools as &$tool) {
			$tool['Test']['__candidates_to_apply'] = $this->numAllowCandidatesForTool($tool['Test']['id'], $id);
			$tool['Test']['__allows']['apply_tool'] = $tool['Test']['__candidates_to_apply'] > 0;
        }

        return $tools;
	}

	/**
	 * Возвращает список назначенных кандидатам данной группы инструментов.
	 *
	 * @param int $id Идентификатор группы
	 *
	 * @return array
	 */
	function getAppointedToolsFor($id)
	{
        return $this->getToolsByPassStatusFor('READY', $id);
	}

	/**
	 * Возвращает список начатых кандидатами данной группы инструментов.
	 *
	 * @param int $id Идентификатор группы
	 *
	 * @return array
	 */
	function getInProgressToolsFor($id)
	{
        return $this->getToolsByPassStatusFor('IN_PROGRESS', $id);
	}

	/**
	 * Возвращает список пройденных кандидатами данной группы инструментов.
	 *
	 * @param int $id Идентификатор группы
	 *
	 * @return array
	 */
	function getCompletedToolsFor($id)
	{
        return $this->getToolsByPassStatusFor('PASSED', $id);
	}

	/**
	 * Возвращает список инструментов с указанным статусом.
	 *
	 * @param string $pass_status
	 * @param int $id Идентификатор группы
	 *
	 * @return array
	 */
	function getToolsByPassStatusFor($pass_status, $id)
	{
	    $id = intval($id);

        $Testing =& $this->getModel('Testing'); /* @var $Testing Testing */
        $Testing->rel('Candidate | Test');
        if (! in_array($pass_status, $Testing->getPassStatuses())) {
            return array();
        }

        $conds = "`Candidate`.`candidate_group_id` = {$id}";
        $conds .= " AND `Testing`.`pass_status` = '{$pass_status}'";
        if (Auth::o()->is('client_admin')) {
            $auth_data = Auth::o()->data();
            $conds .= " AND `Testing`.`client_id` = {$auth_data['client_id']}";
        }
        $conds .= " GROUP BY `Test`.`id`";

        $fields = array(
            "`Test`.*",
            "COUNT(`Testing`.`candidate_id`) AS `candidates`",
        );

        $tools = $Testing->findAll($conds, $fields);
        foreach ($tools as &$tool) {
            $tool["Test"]["__candidates"] = $tool[0]["candidates"];
            unset($tool[0]["candidates"]);
        }

        return $tools;
	}

	/**
	 * Отменяет указанный инструмент для указанной группы.
	 *
	 * @param int $tool_id Идентификатор инструмента
	 * @param int $group_id Идентификатор группы
	 *
	 * @return bool
	 */
	function cancelToolFor($tool_id, $group_id)
	{
        $Testing =& $this->getModel('Testing'); /* @var $Testing Testing */
        $Testing->rel('Candidate');

        $conds = array();
        $conds[]["`Candidate`.`candidate_group_id`"] = $group_id;
        $conds[]["`Testing`.`test_id`"] = $tool_id;
        $conds[]["`Testing`.`pass_status`"] = "READY";
        if (Auth::o()->is('client_admin')) {
            $auth_data = Auth::o()->data();
            $conds[]["`Testing`.`client_id`"] = $auth_data['client_id'];
        }

        $result = false;

        return $Testing->deleteAll($conds);;
	}

	protected function beforeChange_client_id($new, $old)
	{
	    return false;
	}
}

?>